﻿namespace Busconeitor.BusinessLayer.Kernel
{
    using System;
    using System.IO;
    using System.Text;
    using System.util;
    using DataLayer;
    using Domain.Entities;
    using Domain.Utils.HashTable;
    using iTextSharp.text.pdf;
    using iTextSharp.text.pdf.parser;
    using Utils;
    using System.Diagnostics;

    public class Parser
    {
        #region Atributos

        public static readonly int InitialWordsLength = 30000;
        private HashList _wordList;
        private DocumentoEntity _doc;

        #endregion

        #region Constructores

        #endregion

        #region Propiedades

        #endregion

        #region Metodos

        public void ParseDocument(FileInfo fileInfo)
        {
            Debug.WriteLine("procesando documento: " + fileInfo.Name);
            // 1 - leo el documento, lo guarda vacio y arma la estructura de la lista de poste en memoria
            ReadDocument(fileInfo);
            // 2 - lo persisto la tabla terminos, terminos sucio, indices, posteo
            PersistDocument();
        }

        public void ReadDocument(FileInfo fileInfo)
        {
            try
            {
                _doc = new DocumentoEntity();
                // Obtengo el nombre del documento como el nombre del archivo sin el .pdf
                _doc.Name = fileInfo.Name.Substring(0, fileInfo.Name.Length - 4);
                // Seteo la ubucacion del archivo
                _doc.Location = (fileInfo.DirectoryName + "\\" + fileInfo.Name);
                // Tamaño inicial de la TablaHash que recibirá las palabras unicas del documento actual parseado
                _wordList = new HashList(300000);
                var lectorPdf = new PdfReader(_doc.Location);
                // Seteo el número de paginas de archivo PDF
                _doc.PagesCount = lectorPdf.NumberOfPages;
                _doc.MaxTf = 0;
                _doc.Size = fileInfo.Length;

                DocumentDb.SaveDocument(_doc);
                // Creo un objecto lector del contenido de lo que tiene el reader del pdf
                var parser = new PdfReaderContentParser(lectorPdf);
                // Indice absoluto de cada palabra
                var absWordIndex = 0;

                for (var i = 1; i <= lectorPdf.NumberOfPages; i++)
                {
                    Debug.WriteLine("procesando página: " + i + " de " + lectorPdf.NumberOfPages);
                    // TODO: esto es para empezar a  procesar cada pagina del PDF
                    var strategy = parser.ProcessContent(i, new SimpleTextExtractionStrategy());
                    var strWork = new StringTokenizer(strategy.GetResultantText());

                    while (strWork.HasMoreTokens())
                    {
                        // Corrijo el mal parseo
                        var word = WordCleaner.FixWrongParsedWord(strWork.NextToken());
                        // Limpiar palabra, sin acentos, sin letras no a-z0-9, todo en minusculas, punto y coma etc.
                        var wordClean = WordCleaner.CleanWord(word);
                        // Incremento el indice absoluto 
                        absWordIndex++;
                        // Seteo 21 porque es una exageracion una palabra mayor a 21 letras
                        if (wordClean.Length == 0 || word.Length > 21)
                        {
                            continue;
                        }

                        var newTerm = new TerminoEntity(wordClean, word, absWordIndex);
                        var existentTerm = (TerminoEntity)_wordList.Get(newTerm);

                        // Pregunto si existe la palabra
                        if (existentTerm != null)
                        {
                            // si existe solo incremento la frecuencia
                            existentTerm.IncrementarFrecuencia();
                            existentTerm.AgregarTerminoVariado(word, absWordIndex);
                        }
                        else
                        {
                            // sino la agrego a la tabla
                            _wordList.Put(newTerm);
                            newTerm.IncrementarFrecuencia();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public string ReadPdfFile(string fileName)
        {
            var text = new StringBuilder();

            if (File.Exists(fileName))
            {
                var pdfReader = new PdfReader(fileName);

                for (var page = 1; page <= pdfReader.NumberOfPages; page++)
                {
                    ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
                    var currentText = PdfTextExtractor.GetTextFromPage(pdfReader, page, strategy);

                    currentText = Encoding.UTF8.GetString(ASCIIEncoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(currentText)));
                    text.Append(currentText);
                }
                pdfReader.Close();
            }
            return text.ToString();
        }

        /// <summary>
        /// Realiza el procesamiento e invoca la persistencia del documento y sus palabras en la base de datos.
        /// </summary>
        private void PersistDocument()
        {
            _wordList.StartIterator();
            // cada vuelta se analiza una palabra
            while (_wordList.HasNext())
            {
                var termAux = (TerminoEntity)_wordList.Next();
                // la insercion ya verifica si existe la palabra y tiene en cuenta el nr,
                // tambien graba los indices, los terminos sucios de la palabra y su lista de posteo
                TermDb.SaveTerm(_doc, termAux);
            }
        } 

        #endregion
    }
}
